package web

import (
	"fmt"
	"net/http"
	"reflect"
	"time"

	"gitee.com/thubcc/mobile/lte"
	"gitee.com/thubcc/rtlmmap"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/prometheus/common/log"
)

type Handles struct {
	Hs map[string]interface{}
}

func (hs *Handles) Add(port string, handle interface{}) {
	hs.Hs[port] = handle
}

func (hs *Handles) HandleSpecificationAPI(name string) func(c *gin.Context) {
	return func(c *gin.Context) {
		h := c.Param("handle")
		if handle, ok := hs.Hs[h]; ok {
			getValue := reflect.ValueOf(handle)
			methodValue := getValue.MethodByName(name)
			args := []reflect.Value{reflect.ValueOf(c)}
			methodValue.Call(args)
		} else {
			c.JSON(http.StatusOK, Response{fmt.Sprintf("Cannot find %s", h), nil})
		}
	}
}

var (
	GlobHandles     = &Handles{make(map[string]interface{})}
	DefaultRFConfig = RFConfig{
		FreqCenter: Str1int("874.2e6"),
		SampleRate: Str1int("1.92e6"),
		Gain:       Str10int("40.0"),
	}
	upGrader = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

func (hs *Handles) NewHandle(c *gin.Context) {
	h := c.Param("handle")
	if _, ok := hs.Hs[h]; ok {
		force := c.DefaultQuery("force", "false")
		if force == "false" {
			c.JSON(http.StatusOK, Response{"handle has aready installed", nil})
			return
		} else if c.Query("module") == "dev" {
			c.JSON(http.StatusOK, Response{"Device cannot reinstall", nil})
			return
		}
	}
	switch c.Query("module") {
	case "view":
		hs.Hs[h] = NewViewWithHandle(c)
	case "dev":
		hs.Hs[h] = NewDevWithHandle(c)
	case "fmv":
		hs.Hs[h] = NewFMVWithHandle(c)
	case "ltev":
		hs.Hs[h] = NewLTEVWithHandle(c)
	case "ltesv":
		hs.Hs[h] = NewLTESearchViewWithHandle(c)
	default:
		c.JSON(http.StatusOK, Response{"Cannot find module", nil})
	}
}

func CommonParam(c *gin.Context) (port int, config *rtlmmap.Config) {
	port = Str2int(c.DefaultQuery("port", "0"))
	mode := c.DefaultQuery("mode", "lte")
	switch mode {
	case "lte":
		config = &rtlmmap.DefaultLTEConfig
	case "fm":
		config = &rtlmmap.DefaultFMConfig
	default:
		config = &rtlmmap.DefaultLTEConfig
	}
	return
}

func HList(c *gin.Context) {
	c.JSON(http.StatusOK, Response{GlobHandles.Hs, nil})
}

type HRequest struct {
	Cid int `json:"id"`
	Txp int `json:"txp"`
	Rxp int `json:"rxp"`
}

func HChannel(c *gin.Context) {
	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Info("error get connection")
		log.Info(err)
	}
	defer ws.Close()
	var ioc = make(chan HRequest, 1)
	var active = true
	go func() {
		for active {
			var i = HRequest{}
			err := ws.ReadJSON(&i)
			if err != nil {
				log.Info(err)
				if websocket.IsCloseError(err, websocket.CloseGoingAway) {
					active = false
				}
			} else {
				log.Info("change to ", i)
				ioc <- i
			}
		}
	}()
	views := make(map[int]*rtlmmap.View)
	config := &rtlmmap.DefaultLTEConfig
	var v *rtlmmap.View
	var t HRequest
	for active {
		select {
		case t = <-ioc:
			if _, ok := views[t.Rxp]; !ok {
				views[t.Rxp] = rtlmmap.NewRtlView(t.Rxp, config)
			}
			v = views[t.Rxp]
			v.Reset()
		default:
			if v != nil {
				rfd := v.Raw(0, 2)
				v.Run(1)
				rxSym := lte.OFDM_rx(rfd[9600:9600+19200], 6)
				ch := lte.ChannelEstimateDL(rxSym, t.Cid, t.Txp)
				res := lte.ChannelResult{
					Cid:    t.Cid,
					TxPort: t.Txp,
					RxPort: t.Rxp,
					I:      make([]float64, 74),
					Q:      make([]float64, 74),
				}
				chd := ch.GetCh()
				for i, v := range chd[118:] {
					res.I[i] = real(v)
					res.Q[i] = imag(v)
				}
				for i, v := range chd[:64] {
					res.I[i+10] = real(v)
					res.Q[i+10] = imag(v)
				}
				err := ws.WriteJSON(res)
				if err != nil {
					log.Error(err)
					active = false
				}
			} else {
				time.Sleep(time.Second)
			}
		}
	}
}
